package top.chengdongqing.mishop.order

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.domain.PageRequest
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import top.chengdongqing.mishop.common.exception.BadRequestException
import top.chengdongqing.mishop.common.exception.DeletionFailedException
import top.chengdongqing.mishop.common.exception.NotAcceptableException
import top.chengdongqing.mishop.common.pageable.Page1
import top.chengdongqing.mishop.entities.Order
import top.chengdongqing.mishop.entities.OrderEvent
import top.chengdongqing.mishop.entities.OrderItem
import top.chengdongqing.mishop.enums.OrderStatus
import top.chengdongqing.mishop.order.exception.OrderCreationException
import top.chengdongqing.mishop.order.vo.OrderVO
import top.chengdongqing.mishop.repositories.CartRepository
import top.chengdongqing.mishop.repositories.OrderEventRepository
import top.chengdongqing.mishop.repositories.OrderRepository
import top.chengdongqing.mishop.repositories.UserAddressRepository
import top.chengdongqing.mishop.user.address.CityItem
import java.math.BigDecimal
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.concurrent.atomic.AtomicLong

@Service
class OrderService(
    private val orderRepository: OrderRepository,
    private val cartRepository: CartRepository,
    private val addressRepository: UserAddressRepository,
    private val orderEventRepository: OrderEventRepository,
    @Value("\${order.payment-timeout}") private val paymentTimeout: Long
) {

    @Transactional
    fun createOrder(userId: Int, addressId: Int): Int {
        // 查询购物车已选商品
        val cartItems = cartRepository.findAllByUserIdAndIsCheckedTrue(userId)
        if (cartItems.isEmpty()) {
            throw OrderCreationException("购物车中已选商品为空")
        }
        // 查询收货地址信息
        val address = addressRepository.findByIdAndUserId(addressId, userId)
            ?: throw OrderCreationException("收货地址不存在")

        // 商品总价
        val productsAmount = cartItems.map {
            it.sku.price.multiply(BigDecimal(it.quantity))
        }.reduce(BigDecimal::add)
        // 快递费用
        val shippingFee = BigDecimal.ZERO
        // 优惠金额
        val discountAmount = BigDecimal.ZERO
        // 实付金额
        val paidAmount = productsAmount.add(shippingFee).subtract(discountAmount)

        // 构建订单实体
        val order = Order(
            userId = userId,
            orderNumber = generateOrderNumber(),
            productsAmount = productsAmount,
            shippingFee = shippingFee,
            discountAmount = discountAmount,
            paidAmount = paidAmount,
            recipientName = address.recipientName,
            recipientPhone = address.recipientPhone,
            recipientAddress = let {
                val cityItems = jacksonObjectMapper().readValue<List<CityItem>>(address.city)
                val addressUpperPart = cityItems.joinToString(" ") { it.name }
                listOf(addressUpperPart, address.address).joinToString(" ")
            }
        )
        // 构建订单商品明细
        order.items = cartItems.map {
            OrderItem(
                order = order,
                productId = it.product.id,
                skuId = it.sku.id,
                productName = it.product.name,
                skuName = it.sku.name,
                pictureUrl = it.sku.pictureUrl,
                unitPrice = it.sku.price,
                quantity = it.quantity,
                subtotal = it.sku.price.multiply(BigDecimal(it.quantity))
            )
        }

        // 创建订单
        orderRepository.save(order)
        // 创建订单日志记录
        val orderEvent = OrderEvent(
            orderId = order.id,
            userId = userId
        )
        orderEventRepository.save(orderEvent)
        // 删除购物车已选商品
        if (cartRepository.deleteAllByUserIdAndIsCheckedTrue(userId) != cartItems.size) {
            throw DeletionFailedException("购物车数据未正常删除")
        }

        return order.id
    }

    fun findOrder(userId: Int, id: Int): OrderVO {
        val order = orderRepository.findByIdAndUserId(id, userId)
            ?: throw BadRequestException("该订单不存在")
        return OrderVO.of(order)
    }

    fun findAllByPage(userId: Int, keyword: String?, status: OrderStatus?, pageRequest: PageRequest): Page1<OrderVO> {
        val page = orderRepository.findAllByPage(userId, keyword, status, pageRequest).map { OrderVO.of(it) }
        return Page1.of(page)
    }

    fun findOrderEvents(userId: Int, id: Int): OrderEvent {
        return orderEventRepository.findByOrderIdAndUserId(id, userId)
            ?: throw BadRequestException("订单日志不存在")
    }

    @Transactional
    fun cancelOrder(userId: Int, id: Int) {
        val order = orderRepository.findByIdAndUserId(id, userId)
            ?: throw BadRequestException("该订单不存在")
        // 订单已完成或已取消则不能取消
        if (listOf(OrderStatus.COMPLETED, OrderStatus.CANCELED).contains(order.status)) {
            throw NotAcceptableException("当前订单状态不支持取消")
        }

        // 设置订单状态为取消
        order.status = OrderStatus.CANCELED
        orderRepository.save(order)
        // 记录订单日志
        orderEventRepository.findByIdOrNull(id)?.let {
            it.canceledAt = LocalDateTime.now()
            orderEventRepository.save(it)
        }

        // TODO 1.未支付的关闭支付通道 2.符合条件的进入退款流程
    }

    @Transactional
    fun cancelAllUnpaidOrders(): List<Order> {
        // 查询所有超过2小时未支付的订单
        val cutoff = LocalDateTime.now().minusMinutes(paymentTimeout)
        val orders = orderRepository
            .findAllByStatusAndCreatedAtLessThanEqual(OrderStatus.PENDING_PAYMENT, cutoff)

        orders.forEach { order ->
            // 设置订单状态为取消
            order.status = OrderStatus.CANCELED

            // 记录订单日志
            orderEventRepository.findByIdOrNull(order.id)?.also {
                it.canceledAt = LocalDateTime.now()
                orderEventRepository.save(it)
            }

            // TODO 关闭支付通道
        }
        // 批量更新订单状态
        orderRepository.saveAll(orders)

        return orders
    }
}

private val COUNTER = AtomicLong(0)
private val TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")

private fun generateOrderNumber(): String {
    val timePart = LocalDateTime.now().format(TIME_FORMATTER).toLong()
    val counterPart = COUNTER.incrementAndGet() % 100
    return String.format("%014d%02d", timePart, counterPart)
}